/*
 * Copyright (c) 2015. 石头哥哥
 */

package com.comom.manager.kit;

import cn.jpush.api.JPushClient;
import cn.jpush.api.common.resp.APIConnectionException;
import cn.jpush.api.common.resp.APIRequestException;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.Notification;
import com.mengchong.server.hardcode.MobileCode;
import com.mengchong.server.kit.msgsender.HttpSender;
import com.mengchong.server.kit.oss.OssService;
import com.mengchong.server.kit.security.Base64;
import com.mengchong.server.kit.security.Md5;
import com.mengchong.server.model.ValidCode;
import com.mengchong.server.model.vo.ObjectVo;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by chenlei on 15/7/5.
 * PROJECT_NAME: server-java-mengchong
 * PACKAGE_NAME: com.mengchong.server.kit
 */
public class Kits {

    /**
     *
     */
    private static final Logger LOG = LoggerFactory.getLogger(Kits.class);

    /**
     *
     */
    public static final boolean debug = true;

    /**
     * 正则表达式：验证用户名
     */
    public static final String REGEX_USERNAME = "^[a-zA-Z]\\w{5,17}$";

    /**
     * 正则表达式：验证密码
     */
    public static final String REGEX_PASSWORD = "^[a-zA-Z0-9]{6,16}$";

    /**
     * 正则表达式：验证手机号
     */
    public static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$";

    /**
     * 正则表达式：验证邮箱
     */
    public static final String REGEX_EMAIL = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";

    /**
     * 正则表达式：验证汉字
     */
    public static final String REGEX_CHINESE = "^[\u4e00-\u9fa5],{0,}$";

    /**
     * 正则表达式：验证身份证
     */
    public static final String REGEX_ID_CARD = "(^\\d{18}$)|(^\\d{15}$)";

    /**
     * 正则表达式：验证URL
     */
    public static final String REGEX_URL = "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?";

    /**
     * 正则表达式：验证IP地址
     */
    public static final String REGEX_IP_ADDR = "(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)";

    /**
     * 校验用户名
     *
     * @param username
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isUsername(String username) {
        return Pattern.matches(REGEX_USERNAME, username);
    }

    /**
     * 校验密码
     *
     * @param password
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isPassword(String password) {
        return Pattern.matches(REGEX_PASSWORD, password);
    }

    /**
     * 校验手机号
     *
     * @param mobile
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isMobileNO(String mobile) {
        return Pattern.matches(REGEX_MOBILE, mobile);
    }


    /**
     * 校验汉字
     *
     * @param chinese
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isChinese(String chinese) {
        return Pattern.matches(REGEX_CHINESE, chinese);
    }

    /**
     * 校验身份证
     *
     * @param idCard
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isIDCard(String idCard) {
        return Pattern.matches(REGEX_ID_CARD, idCard);
    }

    /**
     * 校验URL
     *
     * @param url
     * @return 校验通过返回true，否则返回false
     */
    public static boolean isUrl(String url) {
        return Pattern.matches(REGEX_URL, url);
    }

    /**
     * 校验IP地址
     *
     * @param ipAddr
     * @return
     */
    public static boolean isIPAddr(String ipAddr) {
        return Pattern.matches(REGEX_IP_ADDR, ipAddr);
    }


    /**
     * 验证邮箱地址是否正确
     *
     * @param email
     * @return
     */
    public static boolean checkEmail(String email) {
        String check = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
        Pattern regex = Pattern.compile(check);
        Matcher matcher = regex.matcher(email);
        return matcher.matches();
    }



    /**
     * 验证邮箱
     *
     * @param email
     * @return
     */
    public static boolean isEmail(String email) {
        String regex = "\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?";
        return Pattern.matches(regex, email);
    }


    /**
     * @param qq
     * @return
     */
    public static boolean isQQ(String qq) {
        return qq.matches("[1-9][0-9]{4,}");
    }


    /**
     * @param encode
     * @return
     */
    public static String urlDecode(String encode) {
        try {
            return URLDecoder.decode(encode, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param encode
     * @return
     */
    public static String urlEncode(String encode) {
        try {
            return URLEncoder.encode(encode, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 构建 服务器资源 url 
     *
     * @param httpServletRequest 获取服务器uri
     * @return
     */
    private static String server_url;

    @Deprecated
    public static String getserverUrl(HttpServletRequest httpServletRequest) {
        if (server_url == null)//local ?!
            server_url = "http://" + httpServletRequest.getServerName() + ":" + httpServletRequest.getServerPort();
        return server_url;
    }


    /**
     * 验证 header
     *
     * @param httpServletRequest
     * @return
     */
    public static boolean validHeader(HttpServletRequest httpServletRequest) {
        if (debug) return true;//valid head always true
        String timestamp = httpServletRequest.getHeader("timestamp");
        String signature = httpServletRequest.getHeader("signature");
        try {
            byte[] bytes = (timestamp + "_" + "asdfgqwe").getBytes("utf-8");
            return Md5.md5(Base64.encode(bytes, 0, bytes.length)).equals(signature);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * builder  msg
     *
     * @param objectVo
     */
    public static void builderObjectVo(ObjectVo objectVo) {
        objectVo.setCode(1);
        objectVo.setMsg("header签名错误");
    }


    /**
     * jpush 调用接口
     */
    /**
     * 点赞、取消点赞、评论文章、回复评论 等调用jpush接口
     */
    private static final String appKey = "7e6708b1ab4bffebf6946823";
    private static final String masterSecret = "f5fdd1f05b7c1f072175cc5d";
    private static final String prefix = "userj_";//约定客户端别名前缀

    /**
     * oss:
     * Access Key ID：    QXlDmk9sOuDMhzd0
     * oss Access Key Secret： OklmqgRmjYzG9OvQoe2HtQkdYx1ueY
     * <p/>
     * 极光推送接口
     * <p/>
     * 创建msg  ---同时调用该接口
     * 1、提出的问题得到回复，入库消息表；
     * 2、回复问题得到别的用户 回复；
     *
     * @param uid
     * @param alert   通知内容   显示在手机的通知栏（状态栏）    用于提示用户的目的
     * @param content 自定义消息内容   不会被SDK展示到通知栏上 用于应用的内部业务逻辑
     */
    public static void jpushNotify(int uid, String alert, String content) {
        JPushClient jpushClient = new JPushClient(masterSecret, appKey, 5);//retry times  5
        // For push, all you need do is to build PushPayload object.
        String alias = prefix + uid;
        PushPayload payload = PushPayload.newBuilder()
                .setPlatform(Platform.android_ios())
                .setAudience(Audience.alias(alias))
                .setNotification(Notification.alert(alert))
                .setMessage(Message.newBuilder()
                        .setMsgContent(content)
                        .build())
                .setOptions(Options.newBuilder()   //apns 生产环境   ，lib  默认是开发环境 (false)
                        .setApnsProduction(true)
                        .build())
                .build();
        try {
            PushResult result = jpushClient.sendPush(payload);
            LOG.info("Got result - " + result);
        } catch (APIConnectionException e) {
            LOG.error("Connection error. Should retry later. ", e);
        } catch (APIRequestException e) {
            LOG.error("Error response from JPush server. Should review and fix it. ", e);
            LOG.info("HTTP Status: " + e.getStatus());
            LOG.info("Error Code: " + e.getErrorCode());
            LOG.info("Error Message: " + e.getErrorMessage());
            LOG.info("Msg ID: " + e.getMsgId());
        }
    }


    /**
     *
     * @param content
     */
    public static boolean  jpushAll(String content) throws APIConnectionException, APIRequestException {
        JPushClient jpushClient = new JPushClient(masterSecret, appKey, 5);//retry times  5
        PushPayload payload = PushPayload.alertAll(content);
//        try {
//
//        } catch (APIConnectionException e) {
//            // Connection error, should retry later
//            LOG.error("Connection error, should retry later", e);
//
//            return false;
//        } catch (APIRequestException e) {
//            // Should review the error, and fix the request
//            LOG.error("Should review the error, and fix the request", e);
//            LOG.info("HTTP Status: " + e.getStatus());
//            LOG.info("Error Code: " + e.getErrorCode());
//            LOG.info("Error Message: " + e.getErrorMessage());
//            return false;
//        }
        PushResult result = jpushClient.sendPush(payload);

        return result.isResultOK();
    }


    /**
     * 宠管家 短信通道机 uri 账号 密码
     */
    private static final String uri = "http://222.73.117.158/msg/";
    private static final String account = "leaorj_youmeng";//账号
    private static final String pswd = "You773859zxc";//密码

    /**
     * 短信发送接口
     *
     * @param mobiles 手机号码，多个号码使用","分割
     * @param code    验证码 当前应用采用纯数字  "20150715152627,0\n1000715152627103200\n"
     */
    public static MobileCode mobileMsgSend(String mobiles, String code) {
        String content = "亲爱的用户，您的验证码是" + code + "," + (ValidCode.expiredTime / 60000L) + "分钟内有效。";//短信内容
        try {
            String returnString = HttpSender.batchSend(uri, account, pswd, mobiles, content, true, null, null);
            return MobileCode.getMobileCode(Integer.parseInt(returnString.substring(returnString.lastIndexOf(",") + 1, returnString.indexOf("\n"))));
        } catch (Exception e) {
            //TODO 处理异常
            e.printStackTrace();
            return null;
        }
    }

    /**
     *
     * @param mobiles
     * @param content
     * @return
     */
    public static MobileCode sendMsg(String mobiles, String content) {
        try {
            String returnString = HttpSender.batchSend(uri, account, pswd, mobiles, content, true, null, null);
            return MobileCode.getMobileCode(Integer.parseInt(returnString.substring(returnString.lastIndexOf(",") + 1, returnString.indexOf("\n"))));
        } catch (Exception e) {
            //TODO 处理异常
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 创建指定数量的随机字符串
     *
     * @param numberFlag 是否是数字
     * @param length
     * @return
     */
    private static final String strTable = "1234567890";

    public static String createNumberRandom(int length) {
        String retStr;
        int len = strTable.length();
        boolean bDone = true;
        do {
            retStr = "";
            int count = 0;
            for (int i = 0; i < length; i++) {
                double dblR = Math.random() * len;
                int intR = (int) Math.floor(dblR);
                char c = strTable.charAt(intR);
                if (('0' <= c) && (c <= '9')) {
                    count++;
                }
                retStr += strTable.charAt(intR);
            }
            if (count >= 2) {
                bDone = false;
            }
        } while (bDone);

        return retStr;
    }

    /**
     * 创建指定数量的随机字符串
     *
     * @param length
     * @return
     */
    private static final String str = "1234567890abcdefghijkmnpqrstuvwxyz";

    public static String createRandom(int length) {
        String retStr;
        int len = str.length();
        boolean bDone = true;
        do {
            retStr = "";
            int count = 0;
            for (int i = 0; i < length; i++) {
                double dblR = Math.random() * len;
                int intR = (int) Math.floor(dblR);
                char c = str.charAt(intR);
                if (('0' <= c) && (c <= '9')) {
                    count++;
                }
                retStr += str.charAt(intR);
            }
            if (count >= 2) {
                bDone = false;
            }
        } while (bDone);

        return retStr;
    }


    /**
     * 上传单个文件到 oss
     *
     * @param ossService
     * @param bucketName
     * @param multipartFile
     * @param uid
     * @param tid
     * @return
     */
    public static String uploadFilesToOss(OssService ossService, String bucketName,
                                          MultipartFile multipartFile,
                                          int uid, int tid) {
        String originalFilename;
        String subffix;
        String key;
        originalFilename = multipartFile.getOriginalFilename();
        //获取文件的后缀名称
        try {
            subffix = originalFilename.substring(originalFilename.lastIndexOf("."));    //文件后缀
        } catch (StringIndexOutOfBoundsException e) {
            subffix = null;
        }
        //new  file name
        originalFilename = fileName(uid, tid);      //获取文件命名
        originalFilename += subffix;     //    文件名

        key = originalFilename;//上传oss key
        //syn upload files
        try {
            ossService.putObject(bucketName, key, (int) multipartFile.getSize(), multipartFile.getInputStream());   // oss interface will close inputStream
            return key;
        } catch (IOException e) {
            if (LOG.isErrorEnabled())
                LOG.error("上传文件到oss异常：" + e.getMessage() + "multipartFile:" + multipartFile.getOriginalFilename());
            return null;
        }
    }


    /**
     * 上传单个文件到 oss
     *
     * @param ossService
     * @param bucketName
     * @param multipartFile
     * @param uid
     * @param tid
     * @return
     */
    public static String uploadFilesToOssWithCut(OssService ossService, String bucketName,
                                          MultipartFile multipartFile,
                                          int uid, int tid) {
        String originalFilename;
        String subffix;
        String key;
        originalFilename = multipartFile.getOriginalFilename();
        //获取文件的后缀名称
        try {
            subffix = originalFilename.substring(originalFilename.lastIndexOf("."));    //文件后缀
        } catch (StringIndexOutOfBoundsException e) {
            subffix = null;
        }
        //new  file name
        originalFilename = fileName(uid, tid);      //获取文件命名
        originalFilename += subffix;     //    文件名

        key = originalFilename;//上传oss key
        //syn upload files
        try {

            ossService.putObject(bucketName, key, (int) multipartFile.getSize(), multipartFile.getInputStream());   // oss interface will close inputStream
            return key;
        } catch (IOException e) {
            if (LOG.isErrorEnabled())
                LOG.error("上传文件到oss异常：" + e.getMessage() + "multipartFile:" + multipartFile.getOriginalFilename());
            return null;
        }
    }

    /**
     * 上传文件到oss
     *
     * @param ossService
     * @param bucketName
     * @param multipartFileMap
     * @param uid
     * @param tid
     * @return
     */
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static ArrayList<String> uploadFilesToOss(
            OssService ossService, String bucketName,
            Map<String, MultipartFile> multipartFileMap,
            int uid, int tid
    ) {


        String originalFilename;
        String subffix;
        ArrayList<String> originfilenames = null;//  clear  ref
        String key;

        //create local folder
//        String realPath = httpServletRequest.getServletContext().getRealPath("/" + folderName);
//        File localFile = new File(realPath);
//        if (!localFile.exists()) localFile.mkdirs();


        //get collection of multipartfile
        Collection<MultipartFile> files = multipartFileMap.values();
        if (files.size() != 0) {
            for (MultipartFile multipartFile : files) {

                if (multipartFile.isEmpty()) continue;//  size ==0

                if (originfilenames == null) originfilenames = new ArrayList<String>();

                originalFilename = multipartFile.getOriginalFilename();
                //获取文件的后缀名称
                try {
                    subffix = originalFilename.substring(originalFilename.lastIndexOf("."));    //文件后缀
                } catch (StringIndexOutOfBoundsException e) {
                    subffix = null;
                }
                //new  file name
                originalFilename = fileName(uid, tid);      //获取文件命名
                originalFilename += subffix;     //    文件名


                try {
                    //used for write local file  : /foldername/file.type
                    //oss file key is:  folderName/file.type  ,the inputStream will be closed
//                FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), new File(realPath + "/" + originalFilename));// write lock files

                    key = originalFilename;//上传oss key
                    originfilenames.add(key);   //本地保存oss文件 key  ：folderName/file.type     //had  add key in cache

                    //syn upload files
                    ossService.putObject(bucketName, key, (int) multipartFile.getSize(), multipartFile.getInputStream());   // oss interface will close inputStream

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //clear files ref
            files.clear();
        }

        return originfilenames;    // return
    }


    /**
     * 文件处理
     * 上传文件处理接口---  存储文件相对路径                 ---  后续处理CDN 同步
     *
     * @param files              上传文件  spring
     * @param httpServletRequest String realPath = request.getServletContext().getRealPath("/video"); 获取上传的路径  如：video  ,pic   ,videoPic
     * @param uid                账户uid
     * @param tid                说说ID   list  /video/originalFilename
     */
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static ArrayList<String> uploadFiles(Collection<MultipartFile> files, HttpServletRequest httpServletRequest, int uid, int tid) {
        String originalFilename;
        String subffix = null;

        ArrayList<String> originfilenames = null;//  clear  ref

        for (MultipartFile multipartFile : files) {

            if (multipartFile.isEmpty()) continue;//  size ==0

            if (originfilenames == null) originfilenames = new ArrayList<String>();

            originalFilename = multipartFile.getOriginalFilename();
            //获取文件的后缀名称
            try {
                subffix = originalFilename.substring(originalFilename.lastIndexOf("."));
            } catch (StringIndexOutOfBoundsException e) {
                subffix = null;
            }
            //new  file name
            originalFilename = fileName(uid, tid);
            String realpath;
            String filepath;
            if (subffix != null) {
                originalFilename += subffix;//
                if (subffix.contains("mp4")) {
                    filepath = "/video";
                    realpath = httpServletRequest.getServletContext().getRealPath(filepath);
                } else if (subffix.contains("jpg")
                        || subffix.contains("png")) {//pic
                    filepath = "/pic";
                    realpath = httpServletRequest.getServletContext().getRealPath(filepath);
                } else {
                    filepath = "/other";
                    realpath = httpServletRequest.getServletContext().getRealPath(filepath);
                }
            } else {
                filepath = "/other";
                realpath = httpServletRequest.getServletContext().getRealPath(filepath);
            }


            try {

                //make dir
                File uploaddir = new File(realpath);
                if (!uploaddir.exists()) uploaddir.mkdirs();

                //write files
                FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), new File(realpath + "/" + originalFilename));

                originfilenames.add(filepath + "/" + originalFilename);//   such as video  .  ：/video/test.mp4
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //last clear file collection
        files.clear();
        //
        return originfilenames;//  may be size equal to zero, or null
    }


    /**
     * 返回 上传文件 命名
     *
     * @param uid
     * @param tid
     * @return uid _tid_uuid
     */
    public static String fileName(int uid, int tid) {
        return uid + "_" + tid + "_" + UUIDRandom.randomUUID().toString();            // uuid
    }


    public static void main(String[] args) {
        String path = ClassLoader.getSystemResource("").getPath().replace("target/classes/", "web/WEB-INF/res/log4j.properties");
        PropertyConfigurator.configure(path);

//        Kits.jpushNotify(123, "有人评论了你的说说", "测试jpush！！！");
//        Kits.mobileMsgSend("18523901314", "1314");
////        jpushNotify();  //
//        String returnString = "20150715152627,78\n1000715152627103200\n";
//        int index = returnString.lastIndexOf(",") + 1;
//        System.out.println(Integer.parseInt(returnString.substring(index, returnString.indexOf("\n"))));
//
//        System.out.println(createNumberRandom(4));

        String src = "1437919337727_asdfgqwe";
//        src = Base64.encode(src.getBytes(), 0, src.getBytes().length);
//        System.out.println("base64:" + src);
//        System.out.println("md5:" + Md5.md5(src));

//        System.out.println(isEmail("502959937@qq.com"));
//        System.out.println(isQQ("654321"));
        System.out.println(isMobileNO("18217608367"));

    }
}
